home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / readcf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-06  |  23.5 KB  |  1,154 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)readcf.c    5.21 (Berkeley) 6/1/90";
  23. static char  rcsid[] = "@(#)$Id: readcf.c,v 5.21.0.15 1991/08/06 18:17:12 paul Exp $";
  24. #endif /* not lint */
  25.  
  26. #include "sendmail.h"
  27.  
  28. #ifdef __STDC__
  29. # ifdef CC_WONT_PROMOTE
  30. static void toomany(char, int);
  31. # else    /* !CC_WONT_PROMOTE */
  32. static void toomany(int, int);
  33. # endif    /* CC_WONT_PROMOTE */
  34. static void fileclass(int, char *, const char *);
  35. static void makemailer(char *);
  36. static char * munchstring(char *);
  37. static char ** makeargv(char *);
  38. #else /* !__STDC__ */
  39. static void toomany();
  40. static void fileclass();
  41. static void makemailer();
  42. static char * munchstring();
  43. static char ** makeargv();
  44. #endif /* __STDC__ */
  45.  
  46. /*
  47. **  READCF -- read control file.
  48. **
  49. **    This routine reads the control file and builds the internal
  50. **    form.
  51. **
  52. **    The file is formatted as a sequence of lines, each taken
  53. **    atomically.  The first character of each line describes how
  54. **    the line is to be interpreted.  The lines are:
  55. **        Dxval        Define macro x to have value val.
  56. **        Cxword        Put word into class x.
  57. **        Fxfile [fmt]    Read file for lines to put into
  58. **                class x.  Use scanf string 'fmt'
  59. **                or "%s" if not present.  Fmt should
  60. **                only produce one string-valued result.
  61. **        Hname: value    Define header with field-name 'name'
  62. **                and value as specified; this will be
  63. **                macro expanded immediately before
  64. **                use.
  65. **        Sn        Use rewriting set n.
  66. **        Rlhs rhs    Rewrite addresses that match lhs to
  67. **                be rhs.
  68. **        Mn arg=val...    Define mailer.  n is the internal name.
  69. **                Args specify mailer parameters.
  70. **        Oxvalue        Set option x to value.
  71. **        Pname=value    Set precedence name to value.
  72. **
  73. **    Parameters:
  74. **        cfname -- control file name.
  75. **
  76. **    Returns:
  77. **        none.
  78. **
  79. **    Side Effects:
  80. **        Builds several internal tables.
  81. */
  82.  
  83. void
  84. readcf(cfname)
  85.     char *cfname;
  86. {
  87.     FILE *cf;
  88.     int ruleset = 0;
  89.     char *q;
  90.     char **pv;
  91.     struct rewrite *rwp = NULL;
  92.     char buf[MAXLINE];
  93.     register char *p;
  94.     char exbuf[MAXLINE];
  95.     char pvpbuf[PSBUFSIZE];
  96.  
  97.     cf = fopen(cfname, "r");
  98.     if (cf == NULL)
  99.     {
  100.         syserr("cannot open %s", cfname);
  101.         exit(EX_OSFILE);
  102.     }
  103.  
  104.     /* setdefuser(); Moved to main.c - see comments there */
  105.     FileName = cfname;
  106.     LineNumber = 0;
  107.     while (fgetfolded(buf, sizeof buf, cf) != NULL)
  108.     {
  109.         /* map $ into \001 (ASCII SOH) for macro expansion */
  110.         for (p = buf; *p != '\0'; p++)
  111.         {
  112.             if (*p != '$')
  113.                 continue;
  114.  
  115.             if (p[1] == '$')
  116.             {
  117.                 /* actual dollar sign.... */
  118.                 (void) strcpy(p, p + 1);
  119.                 continue;
  120.             }
  121.  
  122.             /* convert to macro expansion character */
  123.             *p = '\001';
  124.         }
  125.  
  126.         /* interpret this line */
  127.         switch (buf[0])
  128.         {
  129.           case '\0':
  130.           case '#':        /* comment */
  131.             break;
  132.  
  133.           case 'R':        /* rewriting rule */
  134.             for (p = &buf[1]; *p != '\0' && *p != '\t'; p++)
  135.                 continue;
  136.  
  137.             if (*p == '\0')
  138.             {
  139.                 syserr("invalid rewrite line \"%s\"", buf);
  140.                 break;
  141.             }
  142.  
  143.             /* allocate space for the rule header */
  144.             if (rwp == NULL)
  145.             {
  146.                 RewriteRules[ruleset] = rwp =
  147.                     (struct rewrite *) xalloc(sizeof *rwp);
  148.             }
  149.             else
  150.             {
  151.                 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
  152.                 rwp = rwp->r_next;
  153.             }
  154.             rwp->r_next = NULL;
  155.  
  156.             /* expand and save the LHS */
  157.             *p = '\0';
  158.             expand(&buf[1], exbuf, &exbuf[(sizeof(exbuf)-1)], CurEnv);
  159.             rwp->r_lhs = prescan(exbuf, '\t', pvpbuf);
  160.             if (rwp->r_lhs != NULL)
  161.                 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
  162.  
  163.             /* expand and save the RHS */
  164.             while (*++p == '\t')
  165.                 continue;
  166.             q = p;
  167.             while (*p != '\0' && *p != '\t')
  168.                 p++;
  169.             *p = '\0';
  170.             expand(q, exbuf, &exbuf[(sizeof(exbuf)-1)], CurEnv);
  171.             rwp->r_rhs = prescan(exbuf, '\t', pvpbuf);
  172.             if (rwp->r_rhs != NULL)
  173.                 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
  174.             break;
  175.  
  176.           case 'S':        /* select rewriting set */
  177.             ruleset = atoi(&buf[1]);
  178.             if (ruleset >= MAXRWSETS || ruleset < 0)
  179.             {
  180.                 syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
  181.                 ruleset = 0;
  182.             }
  183.             rwp = NULL;
  184.             break;
  185.  
  186.           case 'D':        /* macro definition */
  187.             define(buf[1], newstr(munchstring(&buf[2])), CurEnv);
  188.             break;
  189.  
  190.           case 'H':        /* required header line */
  191.             (void) chompheader(&buf[1], TRUE);
  192.             break;
  193.  
  194.           case 'C':        /* word class */
  195.           case 'F':        /* word class from file */
  196.             /* read list of words from argument or file */
  197.             if (buf[0] == 'F')
  198.             {
  199.                 /* read from pipe */
  200.                 if (buf[2] == '|')
  201.                 {
  202.                     p = "%s";
  203.                     fileclass(buf[1], &buf[2], p);
  204.                     break;
  205.                 }
  206.                     
  207.                 /* read from file */
  208.                 for (p = &buf[2]; *p != '\0' && !isspace(*p); p++)
  209.                     continue;
  210.                 if (*p == '\0')
  211.                     p = "%s";
  212.                 else
  213.                 {
  214.                     *p = '\0';
  215.                     while (isspace(*++p))
  216.                         continue;
  217.                 }
  218.                 fileclass(buf[1], &buf[2], p);
  219.                 break;
  220.             }
  221.  
  222.             /* scan the list of words and set class for all */
  223.             expand(&buf[2], exbuf, &exbuf[(sizeof(exbuf)-1)], CurEnv);
  224.             for (p = exbuf; *p != '\0'; )
  225.             {
  226.                 register char *wd;
  227.                 char delim;
  228.  
  229.                 while (*p != '\0' && isspace(*p))
  230.                     p++;
  231.                 wd = p;
  232.                 while (*p != '\0' && !isspace(*p))
  233.                     p++;
  234.                 delim = *p;
  235.                 *p = '\0';
  236.                 if (wd[0] != '\0')
  237.                     setclass(buf[1], wd);
  238.                 *p = delim;
  239.             }
  240.             break;
  241.  
  242.           case 'M':        /* define mailer */
  243.             makemailer(&buf[1]);
  244.             break;
  245.  
  246.           case 'O':        /* set option */
  247.             setoption(buf[1], &buf[2], TRUE, FALSE);
  248.             break;
  249.  
  250.           case 'P':        /* set precedence */
  251.             if (NumPriorities >= MAXPRIORITIES)
  252.             {
  253.                 toomany('P', MAXPRIORITIES);
  254.                 break;
  255.             }
  256.             for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
  257.                 continue;
  258.             if (*p == '\0')
  259.                 goto badline;
  260.             *p = '\0';
  261.             Priorities[NumPriorities].pri_name = newstr(&buf[1]);
  262.             Priorities[NumPriorities].pri_val = atoi(++p);
  263.             NumPriorities++;
  264.             break;
  265.  
  266.           case 'T':        /* trusted user(s) */
  267.             p = &buf[1];
  268.             while (*p != '\0')
  269.             {
  270.                 while (isspace(*p))
  271.                     p++;
  272.                 q = p;
  273.                 while (*p != '\0' && !isspace(*p))
  274.                     p++;
  275.                 if (*p != '\0')
  276.                     *p++ = '\0';
  277.                 if (*q == '\0')
  278.                     continue;
  279.                 for (pv = TrustedUsers; *pv != NULL; pv++)
  280.                     continue;
  281.                 if (pv >= &TrustedUsers[MAXTRUST])
  282.                 {
  283.                     toomany('T', MAXTRUST);
  284.                     break;
  285.                 }
  286.                 *pv = newstr(q);
  287.             }
  288.             break;
  289.  
  290.           default:
  291.           badline:
  292.             syserr("unknown control line \"%s\"", buf);
  293.         }
  294.     }
  295.     FileName = NULL;
  296. }
  297. /*
  298. **  TOOMANY -- signal too many of some option
  299. **
  300. **    Parameters:
  301. **        id -- the id of the error line
  302. **        maxcnt -- the maximum possible values
  303. **
  304. **    Returns:
  305. **        none.
  306. **
  307. **    Side Effects:
  308. **        gives a syserr.
  309. */
  310.  
  311. static void
  312. toomany(id, maxcnt)
  313.     char id;
  314.     int maxcnt;
  315. {
  316.     syserr("too many %c lines, %d max", id, maxcnt);
  317. }
  318. /*
  319. **  FILECLASS -- read members of a class from a file
  320. **
  321. **    Parameters:
  322. **        class -- class to define.
  323. **        filename -- name of file to read.
  324. **        fmt -- scanf string to use for match.
  325. **
  326. **    Returns:
  327. **        none
  328. **
  329. **    Side Effects:
  330. **
  331. **        puts all lines in filename that match a scanf into
  332. **            the named class.
  333. */
  334.  
  335. static void
  336. fileclass(class, filename, fmt)
  337.     int class;
  338.     char *filename;
  339.     const char *fmt;
  340. {
  341.     FILE *f;
  342.     char buf[MAXLINE];
  343.  
  344.     if (filename[0] == '|')
  345.         f = popen(&filename[1], "r");
  346.     else
  347.         f = fopen(filename, "r");
  348.     if (f == NULL)
  349.     {
  350.         syserr("cannot open %s", filename);
  351.         return;
  352.     }
  353.  
  354.     while (fgets(buf, sizeof buf, f) != NULL)
  355.     {
  356.         register STAB *s;
  357.         register char *p;
  358.         char wordbuf[MAXNAME+1];
  359.  
  360.         if (sscanf(buf, fmt, wordbuf) != 1)
  361.             continue;
  362.         p = wordbuf;
  363.  
  364.         /*
  365.         **  Break up the match into words.
  366.         */
  367.  
  368.         while (*p != '\0')
  369.         {
  370.             register char *q;
  371.  
  372.             /* strip leading spaces */
  373.             while (isspace(*p))
  374.                 p++;
  375.             if (*p == '\0')
  376.                 break;
  377.  
  378.             /* find the end of the word */
  379.             q = p;
  380.             while (*p != '\0' && !isspace(*p))
  381.                 p++;
  382.             if (*p != '\0')
  383.                 *p++ = '\0';
  384.  
  385.             /* enter the word in the symbol table */
  386.             if (tTd(37, 2))
  387.                 printf("%s added to class %d\n", q, class);
  388.             s = stab(q, ST_CLASS, ST_ENTER);
  389.             setbitn(class, s->s_class);
  390.         }
  391.     }
  392.  
  393.     if (filename[0] == '|')
  394.         (void) pclose(f);
  395.     else
  396.           (void) fclose(f);
  397. }
  398. /*
  399. **  MAKEMAILER -- define a new mailer.
  400. **
  401. **    Parameters:
  402. **        line -- description of mailer.  This is in labeled
  403. **            fields.  The fields are:
  404. **               P -- the path to the mailer
  405. **               F -- the flags associated with the mailer
  406. **               A -- the argv for this mailer
  407. **               S -- the sender rewriting set
  408. **               R -- the recipient rewriting set
  409. **               E -- the eol string
  410. **               M -- the maximum message size
  411. **               C -- the default character set (#if BIT8)
  412. **               X -- the default escape char (#if BIT8)
  413. **            The first word is the canonical name of the mailer.
  414. **
  415. **    Returns:
  416. **        none.
  417. **
  418. **    Side Effects:
  419. **        enters the mailer into the mailer table.
  420. */
  421.  
  422. static void
  423. makemailer(line)
  424.     char *line;
  425. {
  426.     register char *p;
  427.     register struct mailer *m;
  428.     register STAB *s;
  429.     int i;
  430.     char fcode;
  431.     extern int NextMailer;
  432.     extern char *DelimChar;
  433.  
  434.     /* allocate a mailer and set up defaults */
  435.     m = (struct mailer *) xalloc(sizeof *m);
  436.     bzero((char *) m, sizeof *m);
  437.     m->m_mno = NextMailer;
  438.     m->m_eol = "\n";
  439.  
  440.     /* collect the mailer name */
  441.     for (p = line; *p != '\0' && *p != ',' && !isspace(*p); p++)
  442.         continue;
  443.     if (*p != '\0')
  444.         *p++ = '\0';
  445.     m->m_name = newstr(line);
  446.  
  447.     /* now scan through and assign info from the fields */
  448.     while (*p != '\0')
  449.     {
  450.         while (*p != '\0' && (*p == ',' || isspace(*p)))
  451.             p++;
  452.  
  453.         /* p now points to field code */
  454.         fcode = *p;
  455.         while (*p != '\0' && *p != '=' && *p != ',')
  456.             p++;
  457.         if (*p++ != '=')
  458.         {
  459.             syserr("`=' expected");
  460.             return;
  461.         }
  462.         while (isspace(*p))
  463.             p++;
  464.  
  465.         /* p now points to the field body */
  466.         p = munchstring(p);
  467.  
  468.         /* install the field into the mailer struct */
  469.         switch (fcode)
  470.         {
  471.           case 'P':        /* pathname */
  472.             m->m_mailer = newstr(p);
  473.             break;
  474.  
  475.           case 'F':        /* flags */
  476.             for (; *p != '\0'; p++)
  477.                 setbitn(*p, m->m_flags);
  478.             break;
  479.  
  480.           case 'S':        /* sender rewriting ruleset(s) */
  481.           case 'R':        /* recipient rewriting ruleset(s) */
  482.             i = atoi(p);
  483.             if (i < 0 || i >= MAXRWSETS)
  484.             {
  485.                 syserr("invalid rewrite set, %d max", MAXRWSETS);
  486.                 return;
  487.             }
  488.             /* default envelope ruleset for header ruleset */
  489.             if (fcode == 'S')
  490.             {
  491.                 m->m_se_rwset = i;
  492.                 m->m_sh_rwset = i;
  493.             }
  494.             else
  495.             {
  496.                 m->m_re_rwset = i;
  497.                 m->m_rh_rwset = i;
  498.             }
  499.             /* look for specific header rewriting ruleset */
  500.             while (*p != '\0' && *p != ',' && *p != '/') p++;
  501.             if (*p++ == '/')
  502.             {
  503.                 i = atoi(p);
  504.                 if (i < 0 || i >= MAXRWSETS)
  505.                 {
  506.                     syserr("invalid rewrite set, %d max",
  507.                            MAXRWSETS);
  508.                     return;
  509.                 }
  510.             if (fcode == 'S')
  511.                     m->m_sh_rwset = i;
  512.             else
  513.                     m->m_rh_rwset = i;
  514.             }
  515.             break;
  516.  
  517.           case 'E':        /* end of line string */
  518.             m->m_eol = newstr(p);
  519.             break;
  520.  
  521.           case 'A':        /* argument vector */
  522.             m->m_argv = makeargv(p);
  523.             break;
  524.  
  525.           case 'M':        /* maximum message size */
  526.             m->m_maxsize = atol(p);
  527.             break;
  528. #ifdef BIT8
  529.           case 'C':        /* default character set */
  530.             m->m_charset = getchset(newstr(p), 0);
  531.             break;
  532.  
  533.           case 'X':        /* default escape char */
  534.             m->m_esc = atol(p);
  535.             break;
  536. #endif /* BIT8 */
  537.         }
  538.         p = DelimChar;
  539.     }
  540. #ifdef BIT8
  541.     if (m->m_charset)
  542.         m->m_charset->esc = m->m_esc;
  543. #endif /* BIT8 */
  544.  
  545.     /* now store the mailer away */
  546.     if (NextMailer >= MAXMAILERS)
  547.     {
  548.         syserr("too many mailers defined (%d max)", MAXMAILERS);
  549.         return;
  550.     }
  551.     Mailer[NextMailer++] = m;
  552.     s = stab(m->m_name, ST_MAILER, ST_ENTER);
  553.     s->s_mailer = m;
  554. }
  555. /*
  556. **  MUNCHSTRING -- translate a string into internal form.
  557. **
  558. **    Parameters:
  559. **        p -- the string to munch.
  560. **
  561. **    Returns:
  562. **        the munched string.
  563. **
  564. **    Side Effects:
  565. **        Sets "DelimChar" to point to the string that caused us
  566. **        to stop.
  567. */
  568.  
  569. static char *
  570. munchstring(p)
  571.     register char *p;
  572. {
  573.     register char *q;
  574.     bool backslash = FALSE;
  575.     bool quotemode = FALSE;
  576.     static char buf[MAXLINE];
  577.     extern char *DelimChar;
  578.  
  579.     for (q = buf; *p != '\0'; p++)
  580.     {
  581.         if (backslash)
  582.         {
  583.             /* everything is roughly literal */
  584.             backslash = FALSE;
  585.             switch (*p)
  586.             {
  587.               case 'r':        /* carriage return */
  588.                 *q++ = '\r';
  589.                 continue;
  590.  
  591.               case 'n':        /* newline */
  592.                 *q++ = '\n';
  593.                 continue;
  594.  
  595.               case 'f':        /* form feed */
  596.                 *q++ = '\f';
  597.                 continue;
  598.  
  599.               case 'b':        /* backspace */
  600.                 *q++ = '\b';
  601.                 continue;
  602.             }
  603.             *q++ = *p;
  604.         }
  605.         else
  606.         {
  607.             if (*p == '\\')
  608.                 backslash = TRUE;
  609.             else if (*p == '"')
  610.                 quotemode = !quotemode;
  611.             else if (quotemode || *p != ',')
  612.                 *q++ = *p;
  613.             else
  614.                 break;
  615.         }
  616.     }
  617.  
  618.     DelimChar = p;
  619.     *q++ = '\0';
  620.     return (buf);
  621. }
  622. /*
  623. **  MAKEARGV -- break up a string into words
  624. **
  625. **    Parameters:
  626. **        p -- the string to break up.
  627. **
  628. **    Returns:
  629. **        a char **argv (dynamically allocated)
  630. **
  631. **    Side Effects:
  632. **        munges p.
  633. */
  634.  
  635. static char **
  636. makeargv(p)
  637.     register char *p;
  638. {
  639.     char *q;
  640.     int i;
  641.     char **avp;
  642.     char *argv[MAXPV + 1];
  643.  
  644.     /* take apart the words */
  645.     i = 0;
  646.     while (*p != '\0' && i < MAXPV)
  647.     {
  648.         q = p;
  649.         while (*p != '\0' && !isspace(*p))
  650.             p++;
  651.         while (isspace(*p))
  652.             *p++ = '\0';
  653.         argv[i++] = newstr(q);
  654.     }
  655.     argv[i++] = NULL;
  656.  
  657.     /* now make a copy of the argv */
  658.     avp = (char **) xalloc(sizeof *avp * i);
  659.     bcopy((char *) argv, (char *) avp, sizeof *avp * i);
  660.  
  661.     return (avp);
  662. }
  663. /*
  664. **  PRINTRULES -- print rewrite rules (for debugging)
  665. **
  666. **    Parameters:
  667. **        none.
  668. **
  669. **    Returns:
  670. **        none.
  671. **
  672. **    Side Effects:
  673. **        prints rewrite rules.
  674. */
  675.  
  676. void
  677. printrules()
  678. {
  679.     register struct rewrite *rwp;
  680.     register int ruleset;
  681.  
  682.     for (ruleset = 0; ruleset < 10; ruleset++)
  683.     {
  684.         if (RewriteRules[ruleset] == NULL)
  685.             continue;
  686.         printf("\n----Rule Set %d:", ruleset);
  687.  
  688.         for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
  689.         {
  690.             printf("\nLHS:");
  691.             printav(rwp->r_lhs);
  692.             printf("RHS:");
  693.             printav(rwp->r_rhs);
  694.         }
  695.     }
  696. }
  697.  
  698. /*
  699. **  SETOPTION -- set global processing option
  700. **
  701. **    Parameters:
  702. **        opt -- option name.
  703. **        val -- option value (as a text string).
  704. **        safe -- set if this came from a configuration file.
  705. **            Some options (if set from the command line) will
  706. **            reset the user id to avoid security problems.
  707. **        sticky -- if set, don't let other setoptions override
  708. **            this value.
  709. **
  710. **    Returns:
  711. **        none.
  712. **
  713. **    Side Effects:
  714. **        Sets options as implied by the arguments.
  715. */
  716.  
  717. static BITMAP    StickyOpt;        /* set if option is stuck */
  718.  
  719. void
  720. setoption(opt, val, safe, sticky)
  721.     char opt;
  722.     const char *val;
  723.     bool safe;
  724.     bool sticky;
  725. {
  726.     extern int QueueLA;
  727.     extern int RefuseLA;
  728.  
  729.     if (tTd(37, 1))
  730.         printf("setoption %c=%s", opt, val);
  731.  
  732.     /*
  733.     **  See if this option is preset for us.
  734.     */
  735.  
  736.     if (bitnset(opt, StickyOpt))
  737.     {
  738.         if (tTd(37, 1))
  739.             printf(" (ignored)\n");
  740.         return;
  741.     }
  742.  
  743.     /*
  744.     **  Check to see if this option can be specified by this user.
  745.     */
  746.  
  747.     if (!safe && getuid() == 0)
  748.         safe = TRUE;
  749.     if (!safe && index("deiLmorsv", opt) == NULL)
  750.     {
  751.         if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
  752.         {
  753.             if (tTd(37, 1))
  754.                 printf(" (unsafe)");
  755.             if (getuid() != geteuid())
  756.             {
  757.                 printf("(Resetting uid)\n");
  758.                 (void) setgid(getgid());
  759.                 (void) setuid(getuid());
  760.             }
  761.         }
  762.     }
  763.     else if (tTd(37, 1))
  764.         printf("\n");
  765.  
  766.     switch (opt)
  767.     {
  768.       case 'A':        /* set default alias file */
  769.         if (val[0] == '\0')
  770.             AliasFile = "aliases";
  771.         else
  772.             AliasFile = newstr(val);
  773. #if defined(DBM_AUTOBUILD) && (defined(NDBM) || defined(OTHERDBM) )
  774.         DbmTab[DB_ALIAS].db_source = DbmTab[DB_ALIAS].db_name;
  775.         DbmTab[DB_ALIAS].db_rule = "%99[^#:]:%199[ -~    ]\n";
  776. #endif /* DBM_AUTOBUILD && (NDBM || OTHERDBM) */
  777.         break;
  778.  
  779.       case 'a':        /* look N minutes for "@:@" in alias file */
  780.         if (val[0] == '\0')
  781.             SafeAlias = 5;
  782.         else
  783.             SafeAlias = atoi(val);
  784.         break;
  785.  
  786.       case 'B':        /* substitution for blank character */
  787.         SpaceSub = val[0];
  788.         if (SpaceSub == '\0')
  789.             SpaceSub = ' ';
  790.         break;
  791.  
  792.       case 'c':        /* don't connect to "expensive" mailers */
  793.         NoConnect = atobool(val);
  794.         break;
  795.  
  796.       case 'C':        /* checkpoint after N connections */
  797.         CheckPointLimit = atoi(val);
  798.         break;
  799.  
  800.       case 'd':        /* delivery mode */
  801.         switch (*val)
  802.         {
  803.           case '\0':
  804.             SendMode = SM_DELIVER;
  805.             break;
  806.  
  807.           case SM_QUEUE:    /* queue only */
  808. #ifndef QUEUE
  809.             syserr("need QUEUE to set -odqueue");
  810. #endif /* QUEUE */
  811.             /* fall through..... */
  812.  
  813.           case SM_DELIVER:    /* do everything */
  814.           case SM_FORK:        /* fork after verification */
  815.             SendMode = *val;
  816.             break;
  817.  
  818.           default:
  819.             syserr("Unknown delivery mode %c", *val);
  820.             exit(EX_USAGE);
  821.         }
  822.         break;
  823.  
  824.       case 'D':        /* rebuild alias database as needed */
  825.         AutoRebuild = atobool(val);
  826. #if defined(apollo)
  827.         /*
  828.          * Apollo cannot handle multiple processes (perhaps on
  829.          * separate nodes) opening the alias database read-write.
  830.          * So we open it readonly except in INITALIAS mode
  831.          * (see mapinit() in daemon.c).  This makes AutoRebuild
  832.          * impossible.
  833.          */
  834.         if (AutoRebuild)
  835.         {
  836.             syserr("Alias autorebuild (option D) not supported on Apollo");
  837.             exit(EX_USAGE);
  838.         }
  839. #endif /* apollo */
  840.         break;
  841.  
  842.       case 'e':        /* set error processing mode */
  843.         switch (*val)
  844.         {
  845.           case EM_QUIET:    /* be silent about it */
  846.           case EM_MAIL:        /* mail back */
  847.           case EM_BERKNET:    /* do berknet error processing */
  848.           case EM_WRITE:    /* write back (or mail) */
  849.             HoldErrs = TRUE;
  850.             /* fall through... */
  851.  
  852.           case EM_PRINT:    /* print errors normally (default) */
  853.             ErrorMode = *val;
  854.             break;
  855.         }
  856.         break;
  857.  
  858.       case 'F':        /* file mode */
  859.         FileMode = atooct(val) & 0777;
  860.         break;
  861.  
  862.       case 'f':        /* save Unix-style From lines on front */
  863.         SaveFrom = atobool(val);
  864.         break;
  865.  
  866.       case 'g':        /* default gid */
  867.         DefGid = atoi(val);
  868.         break;
  869.  
  870.       case 'H':        /* help file */
  871.         if (val[0] == '\0')
  872.             HelpFile = "sendmail.hf";
  873.         else
  874.             HelpFile = newstr(val);
  875.         break;
  876.  
  877.       case 'I':        /* use internet domain name server */
  878.         UseNameServer = atobool(val);
  879.         break;
  880.  
  881.       case 'i':        /* ignore dot lines in message */
  882.         IgnrDot = atobool(val);
  883.         break;
  884. #if defined(NDBM) || defined(OTHERDBM)
  885.       case 'K':        /* keyed database file */
  886. # ifndef DBM_AUTOBUILD
  887.         if (*val != '\0')
  888.             DbmTab[*val & 0177].db_name = newstr(&val[1]);
  889. # else /* DBM_AUTOBUILD */
  890.         if (*val != '\0')
  891.         {
  892.             char *p;
  893.  
  894.             p = strtok(val+1, " \t"); /* beware the macro newstr */
  895.             DbmTab[*val & 0177].db_name = newstr(p);
  896.             if ((p = strtok((char *)NULL, " \t")) && (*p == '/'))
  897.                 DbmTab[*val & 0177].db_source = newstr(p);
  898.             else
  899.             {
  900.                 DbmTab[*val & 0177].db_source = (char *)NULL;
  901.                 if (!p)
  902.                     break; /* we're outta here */
  903.             }
  904.             if (p = strtok((char *)NULL, ""))
  905.             {
  906.                 /*
  907.                  * start of the rest of the string, or NULL
  908.                  */
  909.  
  910.                 /* fix \-escapes */
  911.                 char    *s;
  912.  
  913.                 for (s = p ; *s; s++)
  914.                 {
  915.                     if (*s == '\\')
  916.                     {
  917.                         char *t, *u;
  918.  
  919.                         u = t = s+1;
  920.                         switch (*t)
  921.                         {
  922. #  ifdef __STDC__
  923.                             case 'a':
  924.                             *s = '\a';
  925.                             u++;
  926.                             break;
  927. #  endif /* __STDC__ */
  928.                             case 'b':
  929.                             *s = '\b';
  930.                             u++;
  931.                             break;
  932.  
  933.                             case 'f':
  934.                             *s = '\f';
  935.                             u++;
  936.                             break;
  937.  
  938.                             case 'n':
  939.                             *s = '\n';
  940.                             u++;
  941.                             break;
  942.  
  943.                             case 'r':
  944.                             *s = '\r';
  945.                             u++;
  946.                             break;
  947.  
  948.                             case 't':
  949.                             *s = '\t';
  950.                             u++;
  951.                             break;
  952. #  ifdef __STDC__
  953.                             case 'v':
  954.                             *s = '\v';
  955.                             u++;
  956.                             break;
  957. #  endif /* __STDC__ */
  958. #  ifdef __STDC__
  959.                             case 'x':
  960.                             {
  961.                                 long x;
  962.  
  963.                                 x = strtol(u, &u, 16);
  964.                                 while (x > 255)
  965.                                     x /= 255;
  966.                                 *s = (char)x;
  967.                                 u++;
  968.                             }
  969.                             break;
  970. #  endif /* __STDC__ */
  971.                             case '0':
  972.                             case '1':
  973.                             case '2':
  974.                             case '3':
  975.                             case '4':
  976.                             case '5':
  977.                             case '6':
  978.                             case '7':
  979.                             *s = '\0';
  980.                             for ( ; ((u-t)<3) && *u && (*u >= '0') && (*u <= '7') ; u++)
  981.                                 *s = (*s * 8)%249 + (*u - '0');
  982.                             break;
  983.  
  984.                             case '\\':    /* do nothing */
  985.                         /*FALLTHROUGH*/
  986. #  ifdef __STDC__
  987.                             case '?':    /* do nothing */
  988.                         /*FALLTHROUGH*/
  989. #  endif /* __STDC__ */
  990.                             case '\'':    /* do nothing */
  991.                         /*FALLTHROUGH*/
  992. #  ifdef __STDC__
  993.                             case '"':    /* do nothing */
  994.                         /*FALLTHROUGH*/
  995. #  endif /* __STDC__ */
  996.                             default:
  997.                             *s = *t;
  998.                             u++;
  999.                             break;
  1000.                         }
  1001.                         /* left shift rest of string */
  1002.                         while (*u)
  1003.                             *t++ = *u++;
  1004.                         *t = '\0';
  1005.                     }
  1006.                 }
  1007.                 DbmTab[*val & 0177].db_rule = newstr(p);
  1008.             }
  1009.             else    /* have a source file but no program or string */
  1010.                 DbmTab[*val & 0177].db_rule = "%99[^:#     ]:%199[ -~    ]\n";
  1011.             if (tTd(37, 1))
  1012.                 printf("db_rule = %s\n", DbmTab[*val & 0177].db_rule);
  1013.             if ((!DbmTab[*val & 0177].db_source) && (DbmTab[*val & 0177].db_rule[0] != '|'))
  1014.                 DbmTab[*val & 0177].db_source = DbmTab[*val & 0177].db_name;
  1015.         }
  1016. # endif /* !DBM_AUTOBUILD */
  1017.         break;
  1018. #endif /* NDBM || OTHERDBM */
  1019.       case 'L':        /* log level */
  1020.         LogLevel = atoi(val);
  1021.         break;
  1022.  
  1023.       case 'M':        /* define macro */
  1024.         define(val[0], newstr(&val[1]), CurEnv);
  1025.         sticky = FALSE;
  1026.         break;
  1027.  
  1028.       case 'm':        /* send to me too */
  1029.         MeToo = atobool(val);
  1030.         break;
  1031.  
  1032.       case 'n':        /* validate RHS in newaliases */
  1033.         CheckAliases = atobool(val);
  1034.         break;
  1035.  
  1036.       case 'N':        /* home (local?) network name */
  1037.         syserr("Option N is obsolete (ON in sendmail.cf or -oN on command line)");
  1038.         break;
  1039.  
  1040.       case 'o':        /* assume old style headers */
  1041.         if (atobool(val))
  1042.             CurEnv->e_flags |= EF_OLDSTYLE;
  1043.         else
  1044.             CurEnv->e_flags &= ~EF_OLDSTYLE;
  1045.         break;
  1046.  
  1047.       case 'P':        /* postmaster copy address for returned mail */
  1048.         PostMasterCopy = newstr(val);
  1049.         break;
  1050.  
  1051.       case 'q':        /* slope of queue only function */
  1052.         QueueFactor = atoi(val);
  1053.         break;
  1054.  
  1055.       case 'Q':        /* queue directory */
  1056.         if (val[0] == '\0')
  1057.             QueueDir = "mqueue";
  1058.         else
  1059.             QueueDir = newstr(val);
  1060.         break;
  1061.  
  1062.       case 'r':        /* read timeout */
  1063.         ReadTimeout = convtime(val);
  1064.         break;
  1065.  
  1066.       case 'S':        /* status file */
  1067.         if (val[0] == '\0')
  1068.             StatFile = "sendmail.st";
  1069.         else
  1070.             StatFile = newstr(val);
  1071.         break;
  1072.  
  1073.       case 's':        /* be super safe, even if expensive */
  1074.         SuperSafe = atobool(val);
  1075.         break;
  1076.  
  1077.       case 'T':        /* queue timeout */
  1078.         TimeOut = convtime(val);
  1079.         /*FALLTHROUGH*/
  1080.  
  1081.       case 't':        /* time zone name */
  1082.         break;
  1083.  
  1084.       case 'u':        /* set default uid */
  1085.         DefUid = atoi(val);
  1086.         /* setdefuser(); Moved to main.c - see comments there */
  1087.         break;
  1088.  
  1089.       case 'v':        /* run in verbose mode */
  1090.         Verbose = atobool(val);
  1091.         break;
  1092.  
  1093.       case 'x':        /* load avg at which to auto-queue msgs */
  1094.         QueueLA = atoi(val);
  1095.         break;
  1096.  
  1097.       case 'X':        /* load avg at which to auto-reject connections */
  1098.         RefuseLA = atoi(val);
  1099.         break;
  1100.  
  1101.       case 'y':        /* work recipient factor */
  1102.         WkRecipFact = atoi(val);
  1103.         break;
  1104.  
  1105.       case 'Y':        /* fork jobs during queue runs */
  1106.         ForkQueueRuns = atobool(val);
  1107.         break;
  1108.  
  1109.       case 'z':        /* work message class factor */
  1110.         WkClassFact = atoi(val);
  1111.         break;
  1112.  
  1113.       case 'Z':        /* work time factor */
  1114.         WkTimeFact = atoi(val);
  1115.         break;
  1116.  
  1117.       case '/':        /* use split envelope/header rewriting */
  1118.         SplitRewriting = TRUE;
  1119.         break;
  1120.  
  1121.       default:
  1122.         break;
  1123.     }
  1124.     if (sticky)
  1125.         setbitn(opt, StickyOpt);
  1126.     return;
  1127. }
  1128. /*
  1129. **  SETCLASS -- set a word into a class
  1130. **
  1131. **    Parameters:
  1132. **        class -- the class to put the word in.
  1133. **        word -- the word to enter
  1134. **
  1135. **    Returns:
  1136. **        none.
  1137. **
  1138. **    Side Effects:
  1139. **        puts the word into the symbol table.
  1140. */
  1141.  
  1142. void
  1143. setclass(class, word)
  1144.     int class;
  1145.     const char *word;
  1146. {
  1147.     register STAB *s;
  1148.  
  1149.     if (tTd(37, 2))
  1150.         printf("%s added to class %d\n", word, class);
  1151.     s = stab(word, ST_CLASS, ST_ENTER);
  1152.     setbitn(class, s->s_class);
  1153. }
  1154.